/*
Basic example of the utilization of JSBase to create a custom class
-------------------------------------------------------------------

function myClass(argsObj) {
	this.init(argsObj);
};

myClass.prototype = new $.jsClasses.JSBase();
myClass.prototype.constructor = myClass;

myClass.members = {
	memberOne: {
		check: [
			utilities.notStrict.nullFilter,
			utilities.strict.isFunction
		],
		defaultValue: function() {
			alert('hola');
		}
	},
	memberTwo: {
		check: [
			{
				twoSubmemberOne: [
					utilities.notStrict.nullFilter,
					utilities.strict.isString
				],
				twoSubmemberTwo: [
					{
						twoSubmemberTwoOne: [
							utilities.notStrict.nullFilter,
							utilities.strict.isString
						],
						twoSubmemberTwoTwo: [
							utilities.notStrict.nullFilter,
							utilities.strict.isNumber
						]
					}
				]
			}
		],
		defaultValue: {
			twoSubmemberOne: 'defaultTwoSubmemberOne',
			twoSubmemberTwo: {
				twoSubmemberTwoOne: 'defaultTwoSubmemberTwoOne',
				twoSubmemberTwoTwo: 0
			}
		}
	},
	memberThree: {
		check: [
			{
				threeSubmemberOne: [
					utilities.notStrict.nullFilter,
					utilities.strict.isString
				],
				threeSubmemberTwo: [
					{
						threeSubmemberTwoOne: [
							utilities.notStrict.nullFilter,
							utilities.strict.isString
						],
						threeSubmemberTwoTwo: [
							utilities.notStrict.nullFilter,
							utilities.strict.isNumber
						]
					}
				]
			}
		],
		defaultValue: {
			threeSubmemberOne: 'defaultThreeSubmemberOne',
			threeSubmemberTwo: {
				threeSubmemberTwoOne: 'defaultThreeSubmemberTwoOne',
				threeSubmemberTwoTwo: 0
			}
		}
	},
	
	memberFour: {
		check: [
			utilities.notStrict.nullFilter,
			utilities.strict.isString
		],
		defaultValue: 'defaultMemberFour',
		getter: {
			fn: function() {
				return this.memberFour;
			},
			name: 'getMemberFour'
		},
		setter: {
			fn: function(value) {
				var result = this.checkMemberSet({
					name: 'memberFour'
					value: value
				});
				if (result.returnedTrue.length == 1)
					this.memberFour = value;
				else 
					throw new TypeError();
			}
			name: 'setMemberFour'
		}
	}
};
-------------------------------------------------------------------
*/
(function($){
	// init $.jsClasses (jquery repository of javascript user classes)
	$.jsClasses = ((typeof($.jsClasses) == 'object') && ($.jsClasses != null))?
		$.jsClasses :
		{};
	
	$.jsClasses.JSBase = function JSBase(argsObj) {
	};
	
	// Static Members
	
	// invoke it with call/apply
	$.jsClasses.JSBase.getObjectPath = function(path) {
		// var initialitation
		var currentObj = this;
		var pathIte = 0;
		// var initialitation [end]
		do {
			currentObj = currentObj[path[pathIte]];
			pathIte++;
		} while(
			(typeof(currentObj) != 'undefined') &&
			(pathIte < path.length)
		);
		return currentObj;
	};
		
	// invoke it with call/apply	
	$.jsClasses.JSBase.setObjectPath = function(argsObj) {
		// 	argsObj: (object)
		//		- path: (array) submembers name in order
		//		- value: the value it will be setted in the last level
		// var initialitation
		var currentObj = this;
		var currentMemberName;
		var pathIte = 0;
		// var initialitation [end]
		while(
			(typeof(currentObj) != 'undefined') &&
			(pathIte < argsObj.path.length - 1)
		) {
			currentMemberName = argsObj.path[pathIte];
			if (!(currentMemberName in currentObj)) {
				currentObj[currentMemberName] = {};
			};
			currentObj = currentObj[currentMemberName];
			pathIte++;
		};
		currentObj[argsObj.path[pathIte]] = argsObj.value;
	};
	
	// Public Members
	
	$.jsClasses.JSBase.prototype.checkMemberSet = function(argsObj) {
		// 	argsObj: (object)
		//		- name: (string) member name
		//		-	value: the value that want to check if it can be setted
		
		// var initialitation
		var self = this;
		var checkIte = 0;
		var currentMember = ('current' in argsObj)?
			argsObj.current :
			{
				check: (argsObj.name in self.constructor.members)?
					self.constructor.members[argsObj.name].check :
					void(0),
				path: [argsObj.name],
				value: argsObj.value
			};
		var result = {
			returnedFalse: [],
			returnedTrue: [],
			returnedUndefined: []
		};
		var submember = {};
		var submemberName;
		var submemberResult = {
			returnedFalse: [],
			returnedTrue: [],
			returnedUndefined: []
		};
		var subcheckIte;
		var subResult;
		// var initialitation [end]
		if ((currentMember.check) && (currentMember.check.length > 0)) {
			do {
				switch (typeof(currentMember.check[checkIte])) {
					case 'function':
						switch(currentMember.check[checkIte](currentMember.value)) {
							case false:
								result.returnedFalse.push(currentMember.path.slice());
								break;
							case void(0):
								result.returnedUndefined.push(currentMember.path.slice());
								break;
						};
						break;
					case 'object':
						if (currentMember.check[checkIte] instanceof Array) {
							subResult = (currentMember.check[checkIte].length > 0) ?
								false :
								true;
							subcheckIte = 0;
							while (
								(!subResult) &&
								(subcheckIte < currentMember.check[checkIte].length)
							) {
								if (currentMember.check[checkIte][subcheckIte](currentMember.value) == true) {
									subResult = true;
								};
								subcheckIte++;
							};
							if (!subResult)
								result.returnedFalse.push(currentMember.path.slice());
						}
						else { // pure Object
							if (typeof(currentMember.value) == 'object') {
								for (submemberName in currentMember.check[checkIte]) {
									submember.check = currentMember.check[checkIte][submemberName];
									submember.path = currentMember.path.slice();
									submember.path.push(submemberName);
									submember.value = (
										(typeof(currentMember.value) != 'undefined') && 
										(currentMember.value != null) && 
										(submemberName in currentMember.value)
									)?
										currentMember.value[submemberName] :
										void(0);
									submemberResult = this.checkMemberSet({
										current: submember,
										name: argsObj.name,
										value: argsObj.value
									});
									for (var resultIte = 0; resultIte < submemberResult.returnedFalse.length; resultIte++) {
										result.returnedFalse.push(submemberResult.returnedFalse[resultIte].slice());
									};
									for (var resultIte = 0; resultIte < submemberResult.returnedTrue.length; resultIte++) {
										result.returnedTrue.push(submemberResult.returnedTrue[resultIte].slice());
									};
									for (var resultIte = 0; resultIte < submemberResult.returnedUndefined.length; resultIte++) {
										result.returnedUndefined.push(submemberResult.returnedUndefined[resultIte].slice());
									};
								};
							}
							else {
								result.returnedFalse.push(currentMember.path.slice());
							};
						};
						break;
				};
				checkIte++;
			} while(
				(result.returnedFalse.length == 0) &&
				(result.returnedUndefined.length == 0) &&
				(checkIte < currentMember.check.length)
			);
			if ((result.returnedFalse.length == 0) &&
					(result.returnedUndefined.length == 0) &&
					(result.returnedTrue.length == 0)) {
				result.returnedTrue.push(currentMember.path.slice());
			};
		};
		return result;
	};
	
	$.jsClasses.JSBase.prototype.init = function(argsObj) {
		// var initialitation
		var memberDefault;
		var memberName;
		var members = argsObj;
		// var initialitation [end]
		for (memberName in this.constructor.members) {
			memberDefault = this.constructor.members[memberName];
			if ((memberDefault.getter != null) && 
					(memberDefault.getter instanceof Object) &&
					('name' in memberDefault.getter)){
				this[memberDefault.getter.name] = memberDefault.getter.fn;
			};
			if ((memberDefault.setter != null) && 
					(memberDefault.setter instanceof Object) &&
					('name' in memberDefault.setter)){
				this[memberDefault.setter.name] = memberDefault.setter.fn;
			};
			if (!(memberName in argsObj)) {
				members[memberName] = void(0);
			};
		};
		this.setMembers(members, true, true);
	};
	
	$.jsClasses.JSBase.prototype.setMembers = function(members, callSetter, setDefault) {
		// var initialitation
		var currentResult;
		var memberDefault;
		var memberName;
		var result = {
			returnedFalse: [],
			returnedUndefined: [],
			returnedTrue: []
		};
		var resultIte;
		var self = this;
		var value;
		// var initialitation [end]
		// iteration over the members passed in members
		for (memberName in members) {
			if ((callSetter) && 
					('setter' in self.constructor.members[memberName]) &&
					(result.returnedFalse.length == 0)) {
				self.constructor.members[memberName].setter.fn.call(self, members[memberName]);
			}
			else {
				currentResult = self.checkMemberSet({
					name: memberName,
					value: members[memberName]
				});
				for (resultIte = 0; resultIte < currentResult.returnedFalse.length; resultIte++) {
					result.returnedFalse.push(currentResult.returnedFalse[resultIte].slice());
				};
				for (resultIte = 0; resultIte < currentResult.returnedTrue.length; resultIte++) {
					result.returnedTrue.push(currentResult.returnedTrue[resultIte].slice());
				};
				for (resultIte = 0; resultIte < currentResult.returnedUndefined.length; resultIte++) {
					result.returnedUndefined.push(currentResult.returnedUndefined[resultIte].slice());
				};
			};
		};
		console.dir(result);
		if (result.returnedFalse.length == 0) {
			if (setDefault) {
				for (resultIte = 0; resultIte < result.returnedUndefined.length; resultIte++) {
					memberName = result.returnedUndefined[resultIte][0];
					if (result.returnedUndefined[resultIte].length == 0) {
						value = self.constructor.members[memberName].defaultValue;
					}
					else {
						memberDefault = {};
						memberDefault[memberName] = self.constructor.members[memberName].defaultValue;
						value = $.jsClasses.JSBase.getObjectPath.call(memberDefault, result.returnedUndefined[resultIte]);
					};
					$.jsClasses.JSBase.setObjectPath.call(self, {
						path: result.returnedUndefined[resultIte],
						value: value
					});
				};
			};
			for (resultIte = 0; resultIte < result.returnedTrue.length; resultIte++) {
				memberName = result.returnedTrue[resultIte][0];
				if (result.returnedTrue[resultIte].length == 0) {
					value = members[memberName];
				}
				else {
					value = $.jsClasses.JSBase.getObjectPath.call(members, result.returnedTrue[resultIte]);
				};
				$.jsClasses.JSBase.setObjectPath.call(self, {
					path: result.returnedTrue[resultIte],
					value: value
				});
			};
		};
		return result;
	};
	
})(jQuery);
